/*
 * tpromise.c
 *
 *  Created on: Jan 24, 2016
 *      Author: root
 */

#include <string.h>
#include "promise.h"
#include "../basic/operator.h"


// 形式  (delay (expr ...))
Cell* op_delay(Scheme *sc) {
	log(sc, "syntax/promise", "op_delay");
	Cell *x;
	//delay就是把表达式转化为一个无参数的闭包
	//例子 (define f (delay (+ 1 1))) (f)
	//例子 (define f (delay 1)) (f)
	x = make_closure(sc, cons(sc, G_NIL, sc->code), sc->env);
	//(x)->_flag = T_PROMISE;
	(x)->_type = PROMISE_TYPE;
	sc->returnValue = x;
	log(sc, "syntax/promise", "op_delay");
	return pop_callstack(sc);
}

// (force (delay (+ 1 2)))
Cell* op_force(Scheme *sc) {
	log(sc, "syntax/promise", "op_force");
	sc->code = first(sc->args);
	if (type_of(sc, sc->code, PROMISE_TYPE)) {
		/* Should change types to closure here */
		push_callstack(sc, cell_op_save_forced, G_NIL, sc->code);
		sc->args = G_NIL;
		sc->op = cell_op_apply;
		log(sc, "syntax/promise", "op_force");
		return G_TRUE;
	} else {
		sc->returnValue = sc->code;
		log(sc, "syntax/promise", "op_force");
		return pop_callstack(sc);
	}
}

Cell* op_save_forced(Scheme *sc) {
	log(sc, "syntax/promise", "op_save_forced");
	/* Save forced value replacing promise */
	memcpy(sc->code, sc->returnValue, sizeof(Cell));
	log(sc, "syntax/promise", "op_save_forced");
	return pop_callstack(sc);
}


// (cons-stream expr-arg expr-code)
// 例子 (cons-stream 1 1)   => (1 . #<PROMISE>)
Cell* op_c0stream(Scheme *sc) {
	log(sc, "syntax/promise", "op_c0stream");
	push_callstack(sc, cell_op_c1stream, G_NIL, cdr(sc->code));
	sc->code = car(sc->code);
	sc->op = cell_op_eval;
	log(sc, "syntax/promise", "op_c0stream");
	return G_TRUE;
}

Cell* op_c1stream(Scheme *sc) {
	log(sc, "syntax/promise", "op_c1stream");
	Cell *x;
	sc->args = sc->returnValue; /* save sc->value to register sc->args for gc */
	x = make_closure(sc, cons(sc, G_NIL, sc->code), sc->env);
	//(x)->_flag = T_PROMISE;
	(x)->_type = PROMISE_TYPE;
	sc->returnValue = cons(sc, sc->args, x);
	log(sc, "syntax/promise", "op_c1stream");
	return pop_callstack(sc);
}

void init_promise_operators(Scheme *sc) {
	ADD_OPERATOR(sc, "$delay", delay);
	ADD_OPERATOR(sc, "force", force);
	ADD_OPERATOR(sc, "$save-forced", save_forced);
	ADD_OPERATOR(sc, "$c0stream", c0stream);
	ADD_OPERATOR(sc, "$c1stream", c1stream);

	ADD_SYNTAX(sc, "delay", delay);
	ADD_SYNTAX(sc, "cons-stream", c0stream);
}
